import { storeKey } from "./constant";
import ModuleCollection from "./module-collection";
import installModule from "./install-module";
import resetStoreState from "./reset-store-state";
import openStrictCheck from "./open-strict-check";
import withMutation from "./with-mutation";

// vuex4不再是单例仓库模式
export default class Store {
  constructor(options) {
    // 收集模块
    this._modules = new ModuleCollection(options);
    // 初始化_state
    this._state = { ...this._modules.root.state } || Object.create(null);
    // 初始化_getters
    this._getters = Object.create(null);

    // 初始化_mutations
    this._mutations = Object.create(null);
    // 初始化_actions
    this._actions = Object.create(null);
    installModule(
      this,
      this._state,
      this._getters,
      this._mutations,
      this._actions,
      [],
      this._modules.root
    );
    resetStoreState(this);

    const storeRaw = this._modules.root._raw;

    this.strict = storeRaw.strict;
    // 开启严格模式
    this.strict && openStrictCheck(this);
    // 是否通过mutation改值的标识
    this.mutationing = false;
    // 触发所有的插件
    storeRaw.plugins.forEach((plugin) => plugin(this));
  }

  get state() {
    return this._state.data;
  }

  get getters() {
    return this._getters;
  }

  commit = (type, payload) => {
    this._mutations[type].forEach((mutation) => {
      withMutation.call(this, () => mutation(payload));
      this._subscribe.forEach((fn) => {
        fn({ type, payload }, this.state);
      });
    });
  };

  dispatch = (type, payload) => {
    return Promise.all(
      this._actions[type].map((action) => {
        if (action.constructor.name === "AsyncFunction") {
          return action(payload);
        } else {
          return new Promise((resolve) => {
            action(payload);
            resolve();
          });
        }
      })
    );
  };

  subscribe = (fn) => {
    this._subscribe = this._subscribe ?? [];
    this._subscribe.push(fn);
  };

  replaceState = (state) => {
    withMutation.call(this, () => (this._state.data = state));
  };

  registerModule = (path, module) => {
    const parentModule = path.reduce((acc, cur) => {
      if (cur === path[path.length - 1]) {
        return acc;
      } else {
        return acc[cur];
      }
    }, this._modules.root._children);
    // 重新收集模块
    this._modules.register(module, path, parentModule);
    // 收集到的新模块
    const newModule = path.reduce((acc, cur) => {
      if (cur === path[path.length - 1]) {
        return acc[cur];
      } else {
        return acc[cur]._children;
      }
    }, this._modules.root._children);
    const _state = path.reduce((acc, cur) => {
      if (cur === path[path.length - 1]) {
        return acc;
      } else {
        return acc[cur];
      }
    }, this._state.data);
    const _getters = path.reduce((acc, cur) => {
      if (cur === path[path.length - 1]) {
        return acc;
      } else {
        return acc[cur];
      }
    }, this._getters);
    // 初始化模块
    installModule(
      this,
      _state,
      _getters,
      this._mutations,
      this._actions,
      path,
      newModule
    );
  };

  hasModule(path) {
    if (typeof path === "string") {
      path = path.split("/");
    }
    return path.reduce((acc, cur) => {
      if (path[path.length - 1] === cur) {
        return acc[cur] ? true : false;
      } else {
        return acc[cur]._children;
      }
    }, this._modules.root._children);
  }

  install(app, injectKey = storeKey) {
    app.provide(injectKey, this);

    // 避免这种方式获取的值是单例
    app.config.globalProperties[`$store_${injectKey}`] = this;
  }
}
